#pragma once

#include <iostream>
#include <vector>
#include <cassert>
#include <string.h>

#define BUFFERDEFAULTSIZE 1024

class Buffer
{
private:
    std::vector<char> _buffer;
    uint64_t _reader_idx;
    uint64_t _writer_idx;
public:
    Buffer()
        :_buffer(BUFFERDEFAULTSIZE),
        _reader_idx(0),
        _writer_idx(0)
    {
    }   

    void* Begin()
    {
        return &(*_buffer.begin());
    }

    /*获取当前的写入起始地址*/
    void* WritePosition()
    {
        return Begin() + _writer_idx;
    }

    /*获取当前的读取起始地址*/
    void* ReadPosition()
    {
        return Begin() + _reader_idx;
    } 

    /*获取缓冲区末尾空闲空间大小 --也就是写偏移之后的剩余空间*/
    uint64_t TailIdleSize()
    {
        return _buffer.size() - _writer_idx;
    }

    /*获取缓冲区起始空闲空间大小 --也就是读偏移之前的空闲空间*/
    uint64_t HeadIdleSize()
    {
        return _reader_idx; 
    }

    /*获取可读数据大小*/
    uint64_t ReadAbleSize()
    {
        return _writer_idx - _reader_idx;
    }

    /*将读偏移向后移动*/
    void MoveReadOffset(uint64_t len)
    {
        assert(len <= ReadAbleSize());
        _reader_idx += len;
    }

    /*将写偏移向后移动*/
    void MoveWriteOffset(uint64_t len)
    {
        assert(len <= TailIdleSize());
        _writer_idx += len;
    }

    /*确保可写空间足够（整体的空间够了就移动数据， 否则扩容)*/
    void EnsureWriteSpace(uint64_t len)
    {
        /*如果末尾空间大小足够，直接返回*/
        if (TailIdleSize() >= len) 
        {
            return;
        }
        /*如果末尾空间不够，则判断加上起始位置的空闲空间大小是否足够*/
        if (len <= TailIdleSize() + HeadIdleSize())
        {
            /*将数据移动到起始位置*/
            uint64_t rsz = ReadAbleSize();  /*把当前数据大小先保存起来*/
            std::copy(ReadPosition(), ReadPosition() + rsz, Begin());  /*把可读数据拷贝到起始位置*/
            _reader_idx = 0;
            _writer_idx = rsz;
        }
        else
        {
            _buffer.resize(_writer_idx + len);
        }

    }

    /*写入数据*/
    void Write(void* data, uint64_t len)
    {
        /*保证有足够空间*/
        EnsureWriteSpace(len);
        /*拷贝数据进去*/
        const char* d = (const char*)data;
        std::copy(d, d + len, WritePosition());
    }
    void WriteAndPush(void* data, uint64_t len)
    {
        Write(data, len);
        MoveWriteOffset(len);
    }

    void WriteString(const std::string& data)
    {
        return Write((void*)data.c_str(), data.size());
    }

    void WriteStringAndPush(const std::string& data)
    {
        WriteString(data);
        MoveWriteOffset(data.size());
    }

    
    void WriteBuffer(Buffer& data)
    {
        return Write(data.ReadPosition(), data.ReadAbleSize());
    }

    void BufferAndPush(Buffer& data)
    {
        WriteBuffer(data);
        MoveWriteOffset(data.ReadAbleSize());
    }

    /*读取数据*/
    void Read(void* buf, uint64_t len)
    {       
        /*要求获取的数据大小必须小于可读数据大小*/
        assert(len <= ReadAbleSize());
        std::copy(ReadPosition(), ReadPosition() + len, buf);
    }

    void ReadAndPop(void* buf, uint64_t len)
    {
        Read(buf, len);
        MoveReadOffset(len);
    }

    std::string ReadAsString(uint64_t len)
    {
        assert(len <= ReadAbleSize());

        std::string str;
        str.resize(len);
        Read(&str[0], str.size());
        return str;
    }

    std::string ReadAsStringAndPop(uint64_t len)
    {
        ReadAsString(len);
        MoveReadOffset(len);
    }

    char* FindCRLF()
    {
        void* res = memchr(ReadPosition(), '\n', ReadAbleSize());
        return (char*)res;
    }

    /*通常获取一行数据， 这种情况针对是*/
    std::string GetLine()
    {
        char* pos = FindCRLF();
        if (pos == nullptr) return "";
        return ReadAsString(pos - (char*)ReadPosition() + 1);
    }
    
    std::string GetLineAndPop()
    {
        std::string str = GetLine();
        MoveReadOffset(str.size());
        return str;
    }

    /*清空缓冲区*/
    void Clear()
    {
        /*只需要将偏移量归零即可 */
    }

};